#include "evdeploy/utils/report/http_client.h"
#include <curl/curl.h>

#define CONNECTTIMEOUT 5
#define TIMEOUT 5

namespace ev
{

CHttpClient::CHttpClient()
{

}

CHttpClient::~CHttpClient()
{
}


int CHttpClient::http_get(const string& strUrl, const map<string,string>& map_headers, string& strRsp)
{
    string strResponse;    

    CURL *curl = NULL;             
    CURLcode res;           

    curl = curl_easy_init();    
    if (curl == NULL) 
    {
        LOG(ERROR) << "http_get: curl_easy_init failed. " ;
        return -1;
    }	

    string strTmp;
    struct curl_slist* headers = NULL;
    for(map<string,string>::const_iterator it=map_headers.begin(); it!=map_headers.end(); ++it)   
    {
        strTmp = it->first + ": " + it->second;
        headers = curl_slist_append(headers, strTmp.c_str());  
    }

    curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());  
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);  

    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, on_write_data);  
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);  

    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
    
    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, CONNECTTIMEOUT);
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, TIMEOUT);

    res = curl_easy_perform(curl);
    if (res != CURLE_OK)
    {
        LOG(ERROR) << "http_get: curl_easy_perform failed, " << res << ", " << curl_easy_strerror(res);

        curl_slist_free_all(headers);
        curl_easy_cleanup(curl);
        return -1;
    }

    strRsp = strResponse;

    curl_slist_free_all(headers);
    curl_easy_cleanup(curl);
    return 0;
}

int CHttpClient::http_put(const string& strUrl, const map<string, string> &map_headers, 
                             const string& strParams, string& strRsp)
{
    string strResponse;

    CURL *curl;
    CURLcode res;

    curl = curl_easy_init();
    if (curl == NULL)
    {
        LOG(ERROR) << "http_put: curl_easy_init failed. " ;
        return -1;
    }

    string strTmp;
    struct curl_slist* headers = NULL;
    for(map<string, string>::const_iterator it=map_headers.begin(); it!=map_headers.end(); ++it)   
    {
        strTmp = it->first + ": " + it->second;
        headers = curl_slist_append(headers, strTmp.c_str());  
    }

    curl_easy_setopt(curl,CURLOPT_URL, strUrl.c_str());
    curl_easy_setopt(curl,CURLOPT_HTTPHEADER, headers); 

    curl_easy_setopt(curl,CURLOPT_CUSTOMREQUEST, "PUT"); 
    curl_easy_setopt(curl,CURLOPT_POSTFIELDS, strParams.c_str());
    curl_easy_setopt(curl,CURLOPT_POSTFIELDSIZE, strParams.length()); 

    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, on_write_data);  
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse); 

    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);

    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, CONNECTTIMEOUT);
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, TIMEOUT);

    res = curl_easy_perform(curl);
    if (res != CURLE_OK)
    {
        LOG(ERROR) << "http_put: curl_easy_perform failed, " << res << ", " << curl_easy_strerror(res);

        curl_slist_free_all(headers);
        curl_easy_cleanup(curl);
        return -1;
    }

    strRsp = strResponse;
    
    curl_slist_free_all(headers);
    curl_easy_cleanup(curl);
    return 0;
}

int CHttpClient::http_post(const string& strUrl, const map<string, string>& http_post_headers_map, 
                              const string& strParams, string& strRsp)
{
    string strResponse;

    CURL *curl;
    CURLcode res;

    curl = curl_easy_init();
    if (curl == NULL)
    {
        LOG(ERROR) << "http_post: curl_easy_init failed. " ;
        return -1;
    }

    string strTmp;
    struct curl_slist* headers = NULL;     
    for(map<string, string>::const_iterator it=http_post_headers_map.begin(); it!=http_post_headers_map.end(); ++it)   
    {
        strTmp = it->first + ": " + it->second;
        headers = curl_slist_append(headers, strTmp.c_str());  
    }

    curl_easy_setopt(curl,CURLOPT_URL, strUrl.c_str());
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST"); 

    curl_easy_setopt(curl,CURLOPT_POSTFIELDS, strParams.c_str()); 
    curl_easy_setopt(curl,CURLOPT_POSTFIELDSIZE, strParams.length()); 

    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, on_write_data);  
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse); 

    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);

    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, CONNECTTIMEOUT);
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, TIMEOUT);

    res = curl_easy_perform(curl);
    if (res != CURLE_OK)
    {
        LOG(ERROR) << "http_post: curl_easy_perform, " << res << ", " << curl_easy_strerror(res);

        curl_slist_free_all(headers);
        curl_easy_cleanup(curl);
        return -1;
    }

    strRsp = strResponse;

    curl_slist_free_all(headers);
    curl_easy_cleanup(curl);
    return 0;
}

int CHttpClient::http_delete(const string& strUrl, const map<string, string>& map_headers, string& strRsp)
{
    string strResponse;    

    CURL *curl = NULL;             
    CURLcode res;           

    curl = curl_easy_init();    
    if (curl == NULL) 
    {
        LOG(ERROR) << "http_delete: curl_easy_init failed. " ;
        return -1;
    }

    string strTmp;
    struct curl_slist* headers = NULL;
    for(map<string,string>::const_iterator it=map_headers.begin(); it!=map_headers.end(); ++it)   
    {
        strTmp = it->first + ": " + it->second;
        headers = curl_slist_append(headers, strTmp.c_str());  
    }

    curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());  
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);  

    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE"); 
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, on_write_data);  
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);  

    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
    
    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, CONNECTTIMEOUT);
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, TIMEOUT);

    res = curl_easy_perform(curl);
    if (res != CURLE_OK) 
    {
        LOG(ERROR) << "http_delete: curl_easy_perform failed, " << res << ", " << curl_easy_strerror(res);

        curl_slist_free_all(headers);
        curl_easy_cleanup(curl);
        return -1;
    }

    strRsp = strResponse;

    curl_slist_free_all(headers);
    curl_easy_cleanup(curl);
    return 0;
}

int CHttpClient::htt_post_file(const string& strUrl, const vector<pair<string,string> >& v_info, 
    const vector<pair<string,string> >& v_file, string& strRsp)
{
    string strResponse; 
    int iret = -1;

    CURLcode res;
    CURL* curl = curl_easy_init();
    if (!curl)
    {
        LOG(ERROR) << "htt_post_file: curl_easy_init failed. " ;
        return -1;
    }

    struct curl_httppost *post = NULL;
    struct curl_httppost *last = NULL;
    for (vector<pair<string,string> >::const_iterator cit = v_info.begin(); cit != v_info.end(); cit++) 
    {
        curl_formadd(&post, &last,CURLFORM_COPYNAME, cit->first.c_str(),
                     CURLFORM_COPYCONTENTS, cit->second.c_str(),CURLFORM_END);
    }
    
    for (vector<pair<string,string> >::const_iterator cit = v_file.begin(); cit != v_file.end(); cit++) 
    {
        curl_formadd(&post, &last,CURLFORM_COPYNAME, cit->first.c_str(),
                    CURLFORM_FILE, cit->second.c_str(),CURLFORM_END);
    }

    curl_slist * option_list = NULL;
    option_list = curl_slist_append(option_list, "Expect:");
    curl_easy_setopt(curl,CURLOPT_NOSIGNAL,1);
    curl_easy_setopt(curl,CURLOPT_HTTPHEADER,option_list);
    curl_easy_setopt(curl,CURLOPT_URL,strUrl.c_str());
    curl_easy_setopt(curl,CURLOPT_HTTPPOST, post);
    curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION, on_write_data);
    curl_easy_setopt(curl,CURLOPT_WRITEDATA,(void *)&strResponse);

    curl_easy_setopt(curl,CURLOPT_HEADER,1);
    curl_easy_setopt(curl,CURLOPT_CONNECTTIMEOUT,CONNECTTIMEOUT);
    curl_easy_setopt(curl,CURLOPT_FOLLOWLOCATION,1);
    res = curl_easy_perform(curl);
    if (res != CURLE_OK)
    {
        LOG(ERROR) << "htt_post_file: curl_easy_perform, " << res << ", " << curl_easy_strerror(res);
    }
    else
    {
        iret = res;
        strRsp = strResponse;
    }

    curl_formfree(post);
    curl_slist_free_all(option_list);
    curl_easy_cleanup(curl);
      
    return iret;
}

size_t CHttpClient::on_write_data(void* buffer, size_t size, size_t nmemb, void* lpVoid)  
{  
    string* str = dynamic_cast<string*>((string*)lpVoid);  
    if( NULL == str || NULL == buffer )  
    {  
        return -1;  
    }  

    char* pData = reinterpret_cast<char*>(buffer);  
    str->append(pData, size * nmemb);  

    return size*nmemb;  
}  

}//end namespace ev
